<?php

namespace catchAdmin\registration\service;

use app\common\lib\Redis;
use app\common\lib\ZhyxMongo;
use app\common\model\Disease;
use app\common\model\FollowHistory;
use app\common\model\Followtask as FollowtaskModel;
use app\common\model\PatientInfo as PatientInfoModel;
use catchAdmin\permissions\model\Users;
use catcher\exceptions\FailedException;
use catcher\Utils;
use MongoDB\BSON\ObjectId;
use catchAdmin\permissions\model\Department;
use think\Paginator;

class ReportService
{
    /**
     * 部门及以下权限
     */
    private function departmentAndBelow()
    {
        $user = request()->user();
        $departmentIds = Department::getChildrenDepartmentIds($user->department_id);
        return (new Users())->whereIn('department_id', $departmentIds)->column('id');
    }

    /**
     * 按肿瘤类型统计患者数
     * @return array
     */
    public function tumorTypePatientNum(): array
    {
        $requestId = request()->param("request_id", "", "string");

        $match = [];
        if (!empty($requestId)) {
            $rnd = Redis::getInstance()->redis->get("advSearch:" . $requestId);
            $rndArr = json_decode($rnd, true, 512, JSON_THROW_ON_ERROR);
            $match = array_merge_recursive($match, $rndArr);
        }

        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];
        $pipLine = [['$match' => $match], ['$group' => ['_id' => null, 'total' => ['$sum' => 1], 'malignantCount' => ['$sum' => ['$cond' => [['$eq' => ['$tumour_type', '1']], 1, 0]]], 'benignCount' => ['$sum' => ['$cond' => [['$eq' => ['$tumour_type', '2']], 1, 0]]], 'dynamicUncertainCount' => ['$sum' => ['$cond' => [['$eq' => ['$tumour_type', '3']], 1, 0]]], 'unknownCount' => ['$sum' => ['$cond' => [['$eq' => ['$tumour_type', '4']], 1, 0]]], 'nonTumorCount' => ['$sum' => ['$cond' => [['$eq' => ['$tumour_type', '5']], 1, 0]]]]], ['$project' => ['_id' => 0, 'total' => 1, 'malignantCount' => 1, 'benignCount' => 1, 'dynamicUncertainCount' => 1, 'nonTumorCount' => 1, 'unknownCount' => 1]]];
        $data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($pipLine);
        return iterator_to_array($data);
    }

    /**
     * 当前任务中患者
     * @return array
     */
    public function currentInTaskPatient(): array
    {

        $task_cond = [];
        //判断权限
        if (!Utils::isSuperAdmin()) {
            $user_id = $this->departmentAndBelow();
            $task_cond[] = ['creator_id', 'in', $user_id];
        }
        $task_cond[] = ['status', '=', 1];

        //查询进行中的随访任务
        $task_ids = (new FollowtaskModel())->getKvData($task_cond);
        $task_ids = array_map(function ($taskId) {
            return new ObjectId($taskId);
        }, $task_ids);

        $pipLine = [['$match' => ['task_id' => ['$in' => $task_ids]]], ['$group' => ['_id' => '$patientId', 'is_effective' => ['$last' => '$is_effective'], 'followStatus' => ['$last' => '$followStatus']]], ['$group' => ['_id' => null, 'totalPatients' => ['$sum' => 1], 'effectivePatients' => ['$sum' => ['$cond' => [['$eq' => ['$is_effective', 1]], 1, 0]]], 'ineffectivePatients' => ['$sum' => ['$cond' => [['$eq' => ['$is_effective', 0]], 1, 0]]], 'noResultPatients' => ['$sum' => ['$cond' => [['$eq' => ['$followStatus', 0]], 1, 0]]]]], ['$project' => ['_id' => 0, 'totalPatients' => 1, 'effectivePatients' => 1, 'ineffectivePatients' => 1, 'noResultPatients' => 1]]];
        $data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($pipLine);
        $data = iterator_to_array($data);

        return [
            'totalPatients' => $data[0]['totalPatients']??0,
            'effectivePatients' => $data[0]['effectivePatients']??0,
            'ineffectivePatients' => $data[0]['ineffectivePatients']??0,
            'noResultPatients' => $data[0]['noResultPatients']??0
        ];
    }

    /**
     * 符合条件的应随访患者
     * @param array $where 条件
     * @return array
     */
    public function eligibleShouldFollowPatient(array $where = []): array
    {
        $req = request()->param();
        $follow_before_lost_num = 0;
        $follow_before_die_num = 0;


        if ((isset($req['outhospital_date'][0]) && !empty($req['outhospital_date'][0])) && (isset($req['outhospital_date'][1]) && !empty($req['outhospital_date'][1]))) {
            $where[] = ['hoList.outhospitalDate', '>=', $req['outhospital_date'][0]];
            $where[] = ['hoList.outhospitalDate', '<=', $req['outhospital_date'][1]];
        }

        //随访时间
        if ((isset($req['follow_time'][0]) && !empty($req['follow_time'][0])) && (isset($req['follow_time'][1]) && !empty($req['follow_time'][1]))) {
            //随访前已失访数
            $before_lost_cond[] = ['lost_access', '=', 1];
            $before_lost_cond[] = ['lost_access_date', '<', $req['follow_time'][0]];
            $before_lost_cond = array_merge($before_lost_cond, $where);
            $follow_before_lost_num = (new PatientInfoModel())->mongoSearch([], [], ['follow_time'])->where($before_lost_cond)->count();

            //随访前已死亡数
            $before_die_cond[] = ['liveStatus', '=', '0'];
            $before_die_cond[] = ['death.deathDate', '<', $req['follow_time'][0]];
            $before_die_cond = array_merge($before_die_cond, $where);
            $follow_before_die_num = (new PatientInfoModel())->mongoSearch([], [], ['follow_time', 'outhospital_date'])->where($before_die_cond)->count();

            //进行中的随访任务条件
            $in_progress_cond[] = ['starttime', '>=', $req['follow_time'][0]];
            $in_progress_cond[] = ['starttime', '<=', $req['follow_time'][1]];
        }

        //符合条件的应随访患者数
        $patientIds = (new PatientInfoModel())->mongoSearch([], [], ['follow_time'])->where($where)->column('patientId');
        $should_patient_num = count($patientIds);

        //判断权限
        if (!Utils::isSuperAdmin()) {
            $user_id = $this->departmentAndBelow();
            $in_progress_cond[] = ['creator_id', 'in', $user_id];
        }

        //查询进行中和已结束的随访任务
        $in_progress_cond[] = ['status', 'in', [1, 2]];
        $task_ids = (new FollowtaskModel())->getKvData($in_progress_cond);
        $task_ids = array_map(function ($taskId) {
            return new ObjectId($taskId);
        }, $task_ids);

        //期间已随访数
        $already_follow_pip = [['$match' => ['task_id' => ['$in' => $task_ids], 'patientId' => ['$in' => $patientIds], 'followStatus' => ['$in' => [1, 2]]]], ['$group' => ['_id' => '$patientId']], ['$count' => 'count']];
        $already_follow_data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($already_follow_pip);
        $already_follow_data = iterator_to_array($already_follow_data);
        $already_follow_num = $already_follow_data[0]['count'] ?? 0;

        //期间暂存数
        $already_temporary_pip = [['$match' => ['task_id' => ['$in' => $task_ids], 'patientId' => ['$in' => $patientIds], 'followStatus' => 2]], ['$group' => ['_id' => '$patientId']], ['$count' => 'count']];
        $already_temporary_data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($already_temporary_pip);
        $already_temporary_data = iterator_to_array($already_temporary_data);
        $already_temporary_num = $already_temporary_data[0]['count'] ?? 0;

        //已随访患者
        $already_data = $this->alreadyAndNotFollowPatient($task_ids, $patientIds);

        //期间未随访
        $not_follow_num = $should_patient_num - ($follow_before_lost_num + $follow_before_die_num + $already_follow_num);

        return [
            //符合条件的应随访人数
            'shouldPatientNum' => $should_patient_num,
            //随访前已失访
            'followBeforeLostNum' => $follow_before_lost_num,
            //随访前已死亡
            'followBeforeDieNum' => $follow_before_die_num,
            //期间已随访
            'alreadyFollowNum' => $already_follow_num,
            //其中暂存
            'alreadyTemporaryNum' => $already_temporary_num,
            //期间未随访
            'notFollowNum' => $not_follow_num,
            //死亡
            'deathNum' => $already_data['deathNum'],
            //生存
            'survivalNum' => $already_data['survivalNum'],
            //无效随访
            'ineffectiveNum' => $already_data['ineffectiveNum'],
            //期间失访
            'lostNum' => $already_data['lostNum'],
            //任务进行中
            'inProgressNum' => $already_data['inProgressNum'],
            //待分配任务
            'waitAllocationNum' => $not_follow_num - $already_data['inProgressNum']
        ];
    }

    /**
     * 已随访患者、未随访患者
     * @param array $task_ids 计划id
     * @param array $patientIds 患者id
     * @return array
     */
    public function alreadyAndNotFollowPatient(array $task_ids = [], array $patientIds = []): array
    {
        $already_pip = [['$match' => ['task_id' => ['$in' => $task_ids], 'patientId' => ['$in' => $patientIds], 'followStatus' => ['$in' => [1, 2]]]], ['$group' => ['_id' => '$patientId', 'is_effective' => ['$last' => '$is_effective'], 'result' => ['$last' => '$result']]], ['$group' => ['_id' => null, 'DeathCount' => ['$sum' => ['$cond' => [['$eq' => ['$result', 19]], 1, 0]]], 'SurvivalCount' => ['$sum' => ['$cond' => [['$and' => [['$eq' => ['$is_effective', 1]], ['$ne' => ['$result', 19]]]], 1, 0]]], 'IneffectiveCount' => ['$sum' => ['$cond' => [['$eq' => ['$is_effective', 0]], 1, 0]]], 'LostCount' => ['$sum' => ['$cond' => [['$in' => ['$result', [8, 10, 16]]], 1, 0]]]]]];
        $already_data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($already_pip);
        $already_num = iterator_to_array($already_data);

        //查询进行中的随访任务
        $in_progress_task_ids = (new FollowtaskModel())->getKvData([['status', '=', 1]]);
        $in_progress_task_ids = array_map(function ($taskId) {
            return new ObjectId($taskId);
        }, $in_progress_task_ids);

        $not_pip = [['$match' => ['task_id' => ['$in' => $in_progress_task_ids], 'patientId' => ['$in' => $patientIds], 'followStatus' => 0]], ['$group' => ['_id' => '$patientId']], ['$count' => 'count']];
        $not_data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($not_pip);
        $not_num = iterator_to_array($not_data);

        return [
            //死亡
            'deathNum' => $already_num[0]['DeathCount'] ?? 0,
            //生存
            'survivalNum' => $already_num[0]['SurvivalCount'] ?? 0,
            //无效随访
            'ineffectiveNum' => $already_num[0]['IneffectiveCount'] ?? 0,
            //期间失访
            'lostNum' => $already_num[0]['LostCount'] ?? 0,
            //任务进行中
            'inProgressNum' => $not_num[0]['count'] ?? 0
        ];
    }

    /**
     * 随访方式分布
     * @param array $where 条件
     * @return array
     */
    public function followModeDistribution(array $where = []): array
    {
        $req = request()->param();

        //随访时间
        if ((isset($req['follow_time'][0]) && !empty($req['follow_time'][0])) && (isset($req['follow_time'][1]) && !empty($req['follow_time'][1]))) {
            //进行中的随访任务条件
            $in_progress_cond[] = ['starttime', '>=', $req['follow_time'][0]];
            $in_progress_cond[] = ['starttime', '<=', $req['follow_time'][1]];
        }

        //符合条件的应随访患者数
        $patientIds = (new PatientInfoModel())->mongoSearch([], [], ['follow_time'])->where($where)->column('patientId');

        //判断权限
        if (!Utils::isSuperAdmin()) {
            $user_id = $this->departmentAndBelow();
            $in_progress_cond[] = ['creator_id', 'in', $user_id];
        }

        //查询进行中和已结束的随访任务
        $in_progress_cond[] = ['status', 'in', [1, 2]];
        $task_ids = (new FollowtaskModel())->getKvData($in_progress_cond);
        $task_ids = array_map(function ($taskId) {
            return new ObjectId($taskId);
        }, $task_ids);

        //期间已随访数
        $mode_pip = [['$match' => ['task_id' => ['$in' => $task_ids], 'patientId' => ['$in' => $patientIds], 'followStatus' => ['$in' => [1, 2]]]], ['$group' => ['_id' => '$patientId', 'mode' => ['$last' => '$mode']]], ['$group' => ['_id' => null, 'phone' => ['$sum' => ['$cond' => [['$eq' => ['$mode', 4]], 1, 0]]], 'wechat' => ['$sum' => ['$cond' => [['$eq' => ['$mode', 1]], 1, 0]]], 'sms' => ['$sum' => ['$cond' => [['$eq' => ['$mode', 2]], 1, 0]]], 'mz_zy' => ['$sum' => ['$cond' => [['$eq' => ['$mode', 5]], 1, 0]]]]]];
        $mode_data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($mode_pip);
        $mode_data = iterator_to_array($mode_data);

        return [
            //电话
            'phoneNum' => $mode_data[0]['phone'] ?? 0,
            //短信
            'smsNum' => $mode_data[0]['sms'] ?? 0,
            //微信
            'wechatNum' => $mode_data[0]['wechat'] ?? 0,
            //门诊/住院
            'mzzyNum' => $mode_data[0]['mz_zy'] ?? 0,
        ];
    }

    /**
     * 无效随访原因统计
     * @param array $where 条件
     * @return array
     */
    public function invalidFollowReason(array $where = []): array
    {
        $req = request()->param();

        $in_progress_cond = [];
        //随访时间
        if (((isset($req['follow_time'][0]) && !empty($req['follow_time'][0]))) && $req['follow_time'][0] !== 'null') {
            $in_progress_cond[] = ['starttime', '>=', $req['follow_time'][0]];
        }

        if (((isset($req['follow_time'][1]) && !empty($req['follow_time'][1]))) && $req['follow_time'][1] !== 'null') {
            $in_progress_cond[] = ['starttime', '>=', $req['follow_time'][1]];
        }

        //符合条件的应随访患者数
        $patientIds = (new PatientInfoModel())->mongoSearch([], [], ['follow_time'])->where($where)->column('patientId');

        //判断权限
        if (!Utils::isSuperAdmin()) {
            $user_id = $this->departmentAndBelow();
            $in_progress_cond[] = ['creator_id', 'in', $user_id];
        }

        //查询进行中和已结束的随访任务
        $in_progress_cond[] = ['status', 'in', [1, 2]];
        $task_ids = (new FollowtaskModel())->getKvData($in_progress_cond);
        $task_ids = array_map(function ($taskId) {
            return new ObjectId($taskId);
        }, $task_ids);

        $pip = [['$match' => ['task_id' => ['$in' => $task_ids], 'patientId' => ['$in' => $patientIds], 'followStatus' => ['$in' => [1, 2]]]], ['$group' => ['_id' => '$patientId', 'result' => ['$last' => '$result']]], ['$group' => ['_id' => null, 'no_answer' => ['$sum' => ['$cond' => [['$eq' => ['$result', 17]], 1, 0]]], 'refuse_follow' => ['$sum' => ['$cond' => [['$eq' => ['$result', 8]], 1, 0]]], 'shutdown' => ['$sum' => ['$cond' => [['$eq' => ['$result', 13]], 1, 0]]], 'empty_number' => ['$sum' => ['$cond' => [['$eq' => ['$result', 10]], 1, 0]]], 'cease' => ['$sum' => ['$cond' => [['$eq' => ['$result', 14]], 1, 0]]], 'not_available' => ['$sum' => ['$cond' => [['$eq' => ['$result', 15]], 1, 0]]], 'wrong_number' => ['$sum' => ['$cond' => [['$eq' => ['$result', 16]], 1, 0]]], 'number_invalid' => ['$sum' => ['$cond' => [['$eq' => ['$result', 9]], 1, 0]]], 'proactively_reject' => ['$sum' => ['$cond' => [['$eq' => ['$result', 12]], 1, 0]]]]]];
        $data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($pip);
        $data = iterator_to_array($data);

        return [
            //无人接听
            'noAnswerNum' => $data[0]['no_answer'] ?? 0,
            //拒绝随访
            'refuseFollowNum' => $data[0]['refuse_follow'] ?? 0,
            //关机
            'shutdownNum' => $data[0]['shutdown'] ?? 0,
            //空号
            'emptyNumberNum' => $data[0]['empty_number'] ?? 0,
            //停机
            'ceaseNum' => $data[0]['cease'] ?? 0,
            //无法接通
            'notAvailableNum' => $data[0]['not_available'] ?? 0,
            //错号
            'wrongNumberNum' => $data[0]['wrong_number'] ?? 0,
            //号码无效
            'numberInvalidNum' => $data[0]['number_invalid'] ?? 0,
            //主动拒接
            'proactivelyRejectNum' => $data[0]['proactively_reject'] ?? 0,
        ];
    }

    /**
     * 肿瘤分布特征
     * @return array
     */
    public function malignantTumorDistribution(): array
    {
        $requestId = request()->param("request_id", "", "string");

        $disease_match = [];
        $disease_match['icdDiseaseTypeList.type'] = '1';

        $match = [];
        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];

        //其他病种是否展示
        $other_diseases_switch = true;

        if (!empty($requestId)) {
            $rnd = Redis::getInstance()->redis->get("advSearch:" . $requestId);
            $rndArr = json_decode($rnd, true, 512, JSON_THROW_ON_ERROR);
            $match = array_merge_recursive($match, $rndArr);
            $all_patient_pip = [['$match' => $match], ['$count' => 'count']];
            $all_patient_data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($all_patient_pip);
            $all_patient_data = iterator_to_array($all_patient_data);
            $allPatientNum = $all_patient_data[0]['count']??0;

            //病种条件
            $bingzhong_ids = [];
            foreach ($match['$and'] as $key => $val) {
                if (isset($val['bz.bingzhongArr.bingzhong_id'])) {
                    $bingzhong_ids[] = new ObjectId($val['bz.bingzhongArr.bingzhong_id']);
                    unset($match['$and'][$key]);
                    $other_diseases_switch = false;
                }
            }

            if (!empty($bingzhong_ids)) {
                $disease_match['_id'] = ['$in' => $bingzhong_ids];
            }

            if (empty($match['$and'])) {
                unset($match['$and']);
            }
        }else{
            $allPatientNum = (new PatientInfoModel())->whereIn('is_in_hospital', [1,2])->count();
        }

        $disease_pip = [['$match' => $disease_match], ['$group' => ['_id' => '$_id', 'diseaseTypeName' => ['$last' => '$diseaseTypeName']]]];
        $disease_data = ZhyxMongo::getInstance()->setCollection('disease_type')->aggregate($disease_pip);

        //恶性肿瘤
        $match['tumour_type'] = '1';

        $ret = [];
        foreach ($disease_data as $key => $val) {
            $bingzhong_id = (string)$val['_id'];
            $match['bz.bingzhongArr.bingzhong_id'] = $bingzhong_id;
            $patient_pip = [['$match' => $match], ['$count' => 'count']];
            $patient_data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($patient_pip);
            $patient_data = iterator_to_array($patient_data);
            $ret[$key]['name'] = $val['diseaseTypeName'];
            $ret[$key]['num'] = $patient_data[0]['count']??0;
        }

        //其他病种
        if ($other_diseases_switch === true) {
            $other_diseases = $allPatientNum  - array_sum(array_column($ret, 'num'));
            $ret[] = [
                'name' => '其他病种',
                'num' => $other_diseases
            ];
        }
        return $ret;
    }

    /**
     * 性别占比分析
     * @return array
     */
    public function genderRatioAnalysis(): array
    {
        $requestId = request()->param("request_id", "", "string");
        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];
        $match['tumour_type'] = '1';
        if (!empty($requestId)) {
            $rnd = Redis::getInstance()->redis->get("advSearch:" . $requestId);
            $rndArr = json_decode($rnd, true, 512, JSON_THROW_ON_ERROR);
            $match = array_merge_recursive($match, $rndArr);
        }

        $pip = [['$match' => $match], ['$group' => ['_id' => '$sex', 'num' => ['$sum' => 1]]]];
        $data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($pip);

        $ret = [];
        foreach ($data as $key => $val) {
            if ($val['_id'] === null) {
                $v['name'] = '未知';
            }else{
                $v['name'] = $val['_id'];
            }
            $v['value'] = $val['num'];
            $ret[] = $v;
        }
        return $ret;
    }

    /**
     * 年龄及确诊均值分析
     * @return array
     */
    public function ageAndMeanAnalysis(): array
    {
        $requestId = request()->param("request_id", "", "string");
        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];
        $match['tumour_type'] = '1';
        if (!empty($requestId)) {
            $rnd = Redis::getInstance()->redis->get("advSearch:" . $requestId);
            $rndArr = json_decode($rnd, true, 512, JSON_THROW_ON_ERROR);
            $match = array_merge_recursive($match, $rndArr);
        }

        $pip = [['$match' => $match], ['$group' => ['_id' => '$first_treat_age', 'num' => ['$sum' => 1]]]];
        $data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($pip);

        $ret = [];
        foreach ($data as $key => $val) {
            if ($val['_id'] <> null) {
                $v['name'] = $val['_id'];
                $v['value'] = $val['num'];
                $ret[] = $v;
            }
        }
        return $ret;
    }

    /**
     * 性别与年龄确诊均值分析
     * @return array
     */
    public function genderAndAgeAnalysis(): array
    {
        $requestId = request()->param("request_id", "", "string");
        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];
        $match['tumour_type'] = '1';
        if (!empty($requestId)) {
            $rnd = Redis::getInstance()->redis->get("advSearch:" . $requestId);
            $rndArr = json_decode($rnd, true, 512, JSON_THROW_ON_ERROR);
            $match = array_merge_recursive($match, $rndArr);
        }

        $pip = [['$match' => $match], ['$group' => ['_id' => ['sex' => '$sex', 'age' => '$first_treat_age'], 'num' => ['$sum' => 1]]]];
        $data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($pip);

        $ret = [];
        foreach ($data as $key => $val) {
            if ($val['_id']['sex'] == '男' && $val['_id']['age'] <> null) {
                $v['name'] = $val['_id']['sex'];
                $v['age'] = $val['_id']['age'];
                $v['value'] = $val['num'];
                $ret['male'][] = $v;
            }

            if ($val['_id']['sex'] == '女' && $val['_id']['age'] <> null) {
                $v['name'] = $val['_id']['sex'];
                $v['age'] = $val['_id']['age'];
                $v['value'] = $val['num'];
                $ret['female'][] = $v;
            }
        }
        return $ret;
    }

    /**
     * 病种与地域特征分析
     * @return array
     */
    public function diseaseAndRegionAnalysis(): array
    {
        $requestId = request()->param("request_id", "", "string");
        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];
        $match['tumour_type'] = '1';
        $match['accountProvince'] = '吉林省';
        if (!empty($requestId)) {
            $rnd = Redis::getInstance()->redis->get("advSearch:" . $requestId);
            $rndArr = json_decode($rnd, true, 512, JSON_THROW_ON_ERROR);
            $match = array_merge_recursive($match, $rndArr);
        }

        //取前10病种
        $bzpip = [['$match' => $match], ['$unwind' => ['path' => '$bz.bingzhongArr', 'preserveNullAndEmptyArrays' => false]], ['$match' => ['bz.bingzhongArr.bingzhong_type' => '1']], ['$match' => $match],['$group' => ['_id' => '$bz.bingzhongArr.bingzhong_name', 'total_count' => ['$sum' => 1], 'bingzhong_id' => ['$first' => '$bz.bingzhongArr.bingzhong_id']]], ['$sort' => ['total_count' => -1]], ['$limit' => 9]];
        $bzdata = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($bzpip);
        $bzdata = iterator_to_array($bzdata);
        $bzids = [];
        foreach ($bzdata as $key => $val) {
            $bzids[] = $val['_id'];
        }

        $pip = [['$match' => $match], ['$unwind' => ['path' => '$bz.bingzhongArr', 'preserveNullAndEmptyArrays' => false]], ['$match' => ['bz.bingzhongArr.bingzhong_type' => '1']], ['$group' => ['_id' => ['bz_name' => '$bz.bingzhongArr.bingzhong_name', 'city' => '$presentCity'], 'total_count' => ['$sum' => 1], 'city' => ['$first' => '$presentCity'], 'bz_name' => ['$first' => '$bz.bingzhongArr.bingzhong_name']]], ['$sort' => ['total_count' => -1]], ['$group' => ['_id' => '$city', 'total_count' => ['$sum' => '$total_count'], 'details' => ['$addToSet' => ['bz_name' => '$bz_name', 'count' => '$total_count']], 'is_ext' => ['$sum' => ['$cond' => ['if' => ['$in' => ['$bz_name', $bzids]], 'then' => '$total_count', 'else' => 0]]]]], ['$sort' => ['total_count' => -1]], ['$limit' => 9], ['$addFields' => ['other' => ['$subtract' => ['$total_count', '$is_ext']]]], ['$addFields' => ['new_details' => ['$filter' => ['input' => '$details', 'as' => 'detail', 'cond' => ['$and' => [['$in' => ['$$detail.bz_name', $bzids]]]]]]]],['$project' => ['details' => false]]];
        $data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($pip);
        $data = iterator_to_array($data);
        foreach($data as $k => &$v){
            $temp = (array)$v["new_details"];
            usort($temp, function($a, $b) use ($bzids) {
                return array_search($a["bz_name"], $bzids) - array_search($b["bz_name"], $bzids);
            });
            $v["new_details"] = $temp;
        }
        return [
            'top10_bz'=>$bzids,
            'bzList'=>$data
        ];
    }

    /**
     * 总体生存情况分析
     * @return array
     */
    public function survivalSituationAnalysis(): array
    {
        $where = [
            ['is_in_hospital', 'in', [1, 2]],
            ['tumour_type', '=', '1']
        ];
        $eligible = $this->eligibleShouldFollowPatient($where);

        //应随访患者总数
        $total_subjects = $eligible['shouldPatientNum'];

        //随访前已失访人数
        $lost_to_follow_up = $eligible['followBeforeLostNum'];

        //随访前已死亡人数
        $dead_before_follow_up = $eligible['followBeforeDieNum'];

        //期间随访人数
        $during_follow_up = $eligible['alreadyFollowNum'];

        //随访率
        $follow_up_rate = ($dead_before_follow_up + $during_follow_up) / $total_subjects * 100;
        $follow_up_rate = number_format($follow_up_rate, 2).'%';

        //期间有效随访人数
        $valid_follow_up = $eligible['survivalNum'];

        //有效随访率
        $valid_follow_rate = ($dead_before_follow_up + $valid_follow_up) / $total_subjects * 100;
        $valid_follow_rate = number_format($valid_follow_rate, 2).'%';

        //期间死亡人数
        $deaths_during_follow_up = $eligible['deathNum'];

        //死亡率
        $death_rate = ($dead_before_follow_up + $deaths_during_follow_up) / $total_subjects * 100;
        $death_rate = number_format($death_rate, 2).'%';

        // 计算生存概率
        $at_risk = $total_subjects - ($lost_to_follow_up + $dead_before_follow_up);

        $time_points = [3, 6, 9, 12, 24, 36, 48, 60];
        $probabilities = [];
        foreach ($time_points as $time_point) {
            $prob = 1.0;
            for ($i = 0; $i < $time_point; $i++) {
                $prob *= ($at_risk - $i - $deaths_during_follow_up) / ($at_risk - $i);
            }
            $probabilities[$time_point.'月'] = number_format($prob * 100, 2).'%';
        }

        return [
            'total_subjects' => $total_subjects,
            'lost_to_follow_up' => $lost_to_follow_up,
            'dead_before_follow_up' => $dead_before_follow_up,
            'during_follow_up' => $during_follow_up,
            'follow_up_rate' => $follow_up_rate,
            'valid_follow_up' => $valid_follow_up,
            'valid_follow_rate' => $valid_follow_rate,
            'deaths_during_follow_up' => $deaths_during_follow_up,
            'death_rate' => $death_rate,
            'probabilities' => $probabilities
        ];
    }

    /**
     * 病种生存情况分析
     * @return array
     */
    public function diseaseTypeAnalysis(): array
    {
        $req = request()->param();
        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];
        $match['tumour_type'] = '1';

        //确诊日期
        if (((isset($req['first_treat_datetime'][0]) && !empty($req['first_treat_datetime'][0]))) && $req['first_treat_datetime'][0] !== 'null') {
            $match['first_treat_datetime']['$gte'] = $req['first_treat_datetime'][0];
        }
        if (((isset($req['first_treat_datetime'][1]) && !empty($req['first_treat_datetime'][1]))) && $req['first_treat_datetime'][1] !== 'null') {
            $match['first_treat_datetime']['$lte'] = $req['first_treat_datetime'][1];
        }

        //出院时间
        if (((isset($req['outhospital_date'][0]) && !empty($req['outhospital_date'][0]))) && $req['outhospital_date'][0] !== 'null') {
            $match['hoList.outhospitalDate']['$gte'] = $req['outhospital_date'][0];
        }
        if (((isset($req['outhospital_date'][1]) && !empty($req['outhospital_date'][1]))) && $req['outhospital_date'][1] !== 'null') {
            $match['hoList.outhospitalDate']['$lte'] = $req['outhospital_date'][1];
        }

        $match2 = [];
        //随访时间
        if (((isset($req['follow_time'][0]) && !empty($req['follow_time'][0]))) && $req['follow_time'][0] !== 'null') {
            $match2['follow.pushtime']['$gte'] = $req['follow_time'][0];
        }
        if (((isset($req['follow_time'][1]) && !empty($req['follow_time'][1]))) && $req['follow_time'][1] !== 'null') {
            $match2['follow.pushtime']['$lte'] = $req['follow_time'][1];
        }

        $match3 = [];
        if (isset($req['bz']) && !empty($req['bz'])) {
            $match3['bz.bingzhong_id'] = ['$in' => $req['bz']];
        }

        $pip = [['$match' => $match], ['$project' => ['_id' => '$_id', 'patientId' => '$patientId', 'shouldFollowNum' => ['$sum' => 1], 'beforeLossNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$lost_access', 1]], 'then' => 1, 'else' => 0]]], 'beforeDieNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$liveStatus', '0']], 'then' => 1, 'else' => 0]]], 'bz' => '$bz.bingzhongArr']], ['$lookup' => ['from' => 'follow', 'localField' => 'patientId', 'foreignField' => 'patientId', 'as' => 'follow']], ['$unwind' => ['path' => '$follow', 'preserveNullAndEmptyArrays' => true]], ['$match' => $match2?: (object)[]], ['$sort' => ['follow.pushtime' => -1]], ['$project' => ['_id' => '$_id', 'patientId' => '$patientId', 'shouldFollowNum' => '$shouldFollowNum', 'beforeLossNum' => '$beforeLossNum', 'beforeDieNum' => '$beforeDieNum', 'alreadyFollowNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.followStatus', 1]], 'then' => 1, 'else' => 0]]], 'effectiveNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.is_effective', 1]], 'then' => 1, 'else' => 0]]], 'dieNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.result', 19]], 'then' => 1, 'else' => 0]]], 'bz' => '$bz']], ['$unwind' => ['path' => '$bz', 'preserveNullAndEmptyArrays' => true]], ['$match' => $match3?: (object)[]], ['$group' => ['_id' => '$bz.bingzhong_id', 'name' => ['$last' => '$bz.bingzhong_name'], 'shouldFollowNum' => ['$sum' => '$shouldFollowNum'], 'beforeLossNum' => ['$sum' => '$beforeLossNum'], 'beforeDieNum' => ['$sum' => '$beforeDieNum'], 'alreadyFollowNum' => ['$sum' => '$alreadyFollowNum'], 'effectiveNum' => ['$sum' => '$effectiveNum'], 'dieNum' => ['$sum' => '$dieNum']]]];
        $data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($pip, ['allowDiskUse' => true]);
        $data = iterator_to_array($data);
        return $this->kmSurvivalRate($data);
    }

    /**
     * 科室情况分析
     * @return array
     */
    public function deptAnalysis(): array
    {
        $req = request()->param();
        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];
        $match['tumour_type'] = '1';

        //确诊日期
        if (((isset($req['first_treat_datetime'][0]) && !empty($req['first_treat_datetime'][0]))) && $req['first_treat_datetime'][0] !== 'null') {
            $match['first_treat_datetime']['$gte'] = $req['first_treat_datetime'][0];
        }
        if (((isset($req['first_treat_datetime'][1]) && !empty($req['first_treat_datetime'][1]))) && $req['first_treat_datetime'][1] !== 'null') {
            $match['first_treat_datetime']['$lte'] = $req['first_treat_datetime'][1];
        }

        //出院时间
        if (((isset($req['outhospital_date'][0]) && !empty($req['outhospital_date'][0]))) && $req['outhospital_date'][0] !== 'null') {
            $match['hoList.outhospitalDate']['$gte'] = $req['outhospital_date'][0];
        }
        if (((isset($req['outhospital_date'][1]) && !empty($req['outhospital_date'][1]))) && $req['outhospital_date'][1] !== 'null') {
            $match['hoList.outhospitalDate']['$lte'] = $req['outhospital_date'][1];
        }

        $match2 = [];
        //随访时间
        if (((isset($req['follow_time'][0]) && !empty($req['follow_time'][0]))) && $req['follow_time'][0] !== 'null') {
            $match2['follow.pushtime']['$gte'] = $req['follow_time'][0];
        }
        if (((isset($req['follow_time'][1]) && !empty($req['follow_time'][1]))) && $req['follow_time'][1] !== 'null') {
            $match2['follow.pushtime']['$lte'] = $req['follow_time'][1];
        }

        $match3 = [];
        if (isset($req['inhospitalDept']) && !empty($req['inhospitalDept'])) {
            $match3['inhospitalDept'] = ['$in' => $req['inhospitalDept']];
        }

        $pip = [['$match' => $match], ['$project' => ['_id' => '$_id', 'patientId' => '$patientId', 'shouldFollowNum' => ['$sum' => 1], 'beforeLossNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$lost_access', 1]], 'then' => 1, 'else' => 0]]], 'beforeDieNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$liveStatus', '0']], 'then' => 1, 'else' => 0]]], 'inhospitalDeptCode' => '$hoList.inhospitalDeptCode', 'inhospitalDept' => '$hoList.inhospitalDept']], ['$lookup' => ['from' => 'follow', 'localField' => 'patientId', 'foreignField' => 'patientId', 'as' => 'follow']], ['$unwind' => ['path' => '$follow', 'preserveNullAndEmptyArrays' => true]], ['$match' => $match2?: (object)[]], ['$sort' => ['follow.pushtime' => -1]], ['$project' => ['_id' => '$_id', 'patientId' => '$patientId', 'shouldFollowNum' => '$shouldFollowNum', 'beforeLossNum' => '$beforeLossNum', 'beforeDieNum' => '$beforeDieNum', 'alreadyFollowNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.followStatus', 1]], 'then' => 1, 'else' => 0]]], 'effectiveNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.is_effective', 1]], 'then' => 1, 'else' => 0]]], 'dieNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.result', 19]], 'then' => 1, 'else' => 0]]], 'inhospitalDeptCode' => '$inhospitalDeptCode', 'inhospitalDept' => '$inhospitalDept']], ['$match' => $match3?: (object)[]], ['$group' => ['_id' => '$inhospitalDeptCode', 'name' => ['$last' => '$inhospitalDept'], 'shouldFollowNum' => ['$sum' => '$shouldFollowNum'], 'beforeLossNum' => ['$sum' => '$beforeLossNum'], 'beforeDieNum' => ['$sum' => '$beforeDieNum'], 'alreadyFollowNum' => ['$sum' => '$alreadyFollowNum'], 'effectiveNum' => ['$sum' => '$effectiveNum'], 'dieNum' => ['$sum' => '$dieNum']]]];
        $data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($pip, ['allowDiskUse' => true]);
        $data = iterator_to_array($data);
        return $this->kmSurvivalRate($data);
    }

    /**
     * 医生情况分析
     * @return array
     */
    public function doctorAnalysis(): array
    {
        $req = request()->param();
        $match['deleted_at'] = 0;
        $match['is_in_hospital'] = ['$in' => [1, 2]];
        $match['tumour_type'] = '1';

        //确诊日期
        if (((isset($req['first_treat_datetime'][0]) && !empty($req['first_treat_datetime'][0]))) && $req['first_treat_datetime'][0] !== 'null') {
            $match['first_treat_datetime']['$gte'] = $req['first_treat_datetime'][0];
        }
        if (((isset($req['first_treat_datetime'][1]) && !empty($req['first_treat_datetime'][1]))) && $req['first_treat_datetime'][1] !== 'null') {
            $match['first_treat_datetime']['$lte'] = $req['first_treat_datetime'][1];
        }

        //出院时间
        if (((isset($req['outhospital_date'][0]) && !empty($req['outhospital_date'][0]))) && $req['outhospital_date'][0] !== 'null') {
            $match['hoList.outhospitalDate']['$gte'] = $req['outhospital_date'][0];
        }
        if (((isset($req['outhospital_date'][1]) && !empty($req['outhospital_date'][1]))) && $req['outhospital_date'][1] !== 'null') {
            $match['hoList.outhospitalDate']['$lte'] = $req['outhospital_date'][1];
        }

        $match2 = [];
        //随访时间
        if (((isset($req['follow_time'][0]) && !empty($req['follow_time'][0]))) && $req['follow_time'][0] !== 'null') {
            $match2['follow.pushtime']['$gte'] = $req['follow_time'][0];
        }
        if (((isset($req['follow_time'][1]) && !empty($req['follow_time'][1]))) && $req['follow_time'][1] !== 'null') {
            $match2['follow.pushtime']['$lte'] = $req['follow_time'][1];
        }

        if (isset($req['inchargeDoctorNo']) && !empty($req['inchargeDoctorNo'])) {
            $match2['inchargeDoctorNo'] = ['$in' => $req['inchargeDoctorNo']];
        }

        $pip = [['$match' => $match], ['$project' => ['_id' => '$_id', 'patientId' => '$patientId', 'shouldFollowNum' => ['$sum' => 1], 'beforeLossNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$lost_access', 1]], 'then' => 1, 'else' => 0]]], 'beforeDieNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$liveStatus', '0']], 'then' => 1, 'else' => 0]]], 'inchargeDoctorNo' => '$first_doctor_code', 'inchargeDoctorName' => '$first_doctor_name']], ['$lookup' => ['from' => 'follow', 'localField' => 'patientId', 'foreignField' => 'patientId', 'as' => 'follow']], ['$unwind' => ['path' => '$follow', 'preserveNullAndEmptyArrays' => true]], ['$match' => $match2?: (object)[]], ['$sort' => ['follow.pushtime' => -1]], ['$project' => ['_id' => '$_id', 'patientId' => '$patientId', 'shouldFollowNum' => '$shouldFollowNum', 'beforeLossNum' => '$beforeLossNum', 'beforeDieNum' => '$beforeDieNum', 'alreadyFollowNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.followStatus', 1]], 'then' => 1, 'else' => 0]]], 'effectiveNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.is_effective', 1]], 'then' => 1, 'else' => 0]]], 'dieNum' => ['$sum' => ['$cond' => ['if' => ['$eq' => ['$follow.result', 19]], 'then' => 1, 'else' => 0]]], 'inchargeDoctorNo' => '$inchargeDoctorNo', 'inchargeDoctorName' => '$inchargeDoctorName']], ['$group' => ['_id' => '$inchargeDoctorNo', 'name' => ['$last' => '$inchargeDoctorName'], 'shouldFollowNum' => ['$sum' => '$shouldFollowNum'], 'beforeLossNum' => ['$sum' => '$beforeLossNum'], 'beforeDieNum' => ['$sum' => '$beforeDieNum'], 'alreadyFollowNum' => ['$sum' => '$alreadyFollowNum'], 'effectiveNum' => ['$sum' => '$effectiveNum'], 'dieNum' => ['$sum' => '$dieNum']]], ['$sort' => ['shouldFollowNum' => -1]]];
        $data = ZhyxMongo::getInstance()->setCollection('patient_info')->aggregate($pip, ['allowDiskUse' => true]);
        $data = iterator_to_array($data);
        return $this->kmSurvivalRate($data);
    }

    /**
     * 电话接通率
     * @param int $type 类型 1科室，2随访人员，3病种
     * @return array
     */
    public function telCompletionRate(int $type): array
    {
        $requestData = request()->param();

        $bzMatch = (object) array();
        $match2 = (object) array();
        switch ($type) {
            case 1:
                $groupId = '$deptId';
                $groupField = '$deptId';
                //$match2 = ['deptId' => ['$nin' => [null, '', '--']]];
                break;
            case 2:
                $groupId = '$follow_staff.user_id';
                $groupField = '$follow_staff.username';
                break;
            case 3:
                $groupId = '$bz.bingzhong_id';
                $groupField = '$bz.bingzhong_name';
                $bzMatch = ['bz.bingzhongArr.bingzhong_type' => '1'];
                break;
            default:
                throw new FailedException("统计类型错误");
        }

        $match['deleted_at'] = 0;
        $match['followStatus'] = 1;
        $match['mode'] = 4;

        if (isset($requestData['follow_time'][0]) && !empty($requestData['follow_time'][0])){
            $match['pushtime']['$gte'] = $requestData['follow_time'][0];
        }
        if (isset($requestData['follow_time'][1]) && !empty($requestData['follow_time'][1])){
            $match['pushtime']['$lte'] = $requestData['follow_time'][1];
        }

        $pip = [['$match' => $match],['$unwind' => ['path' => '$bz.bingzhongArr', 'preserveNullAndEmptyArrays' => false]],['$match' => $bzMatch], ['$group' => ['_id' => '$patientId', 'id' => ['$last' => '$_id'], 'patientId' => ['$last' => '$patientId'], 'is_effective' => ['$last' => '$is_effective'], 'result' => ['$last' => '$result'], 'resultName' => ['$last' => '$resultName'], 'deptId' => ['$last' => '$patientDeptId'], 'follow_staff' => ['$last' => '$follow_staff'], 'bz' => ['$last' => '$bz.bingzhongArr']]], ['$lookup' => ['from' => 'follow_history', 'localField' => 'id', 'foreignField' => 'follow_id', 'as' => 'history']], ['$addFields' => ['history_count' => ['$size' => '$history'], 'successCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.resultIsEffective', 1]], ['$add' => ['$$value', 1]], '$$value']]]], 'stopCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 14]], ['$add' => ['$$value', 1]], '$$value']]]], 'noAnswerCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 17]], ['$add' => ['$$value', 1]], '$$value']]]], 'emptyCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 10]], ['$add' => ['$$value', 1]], '$$value']]]], 'wrongCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 16]], ['$add' => ['$$value', 1]], '$$value']]]], 'refuseCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 8]], ['$add' => ['$$value', 1]], '$$value']]]], 'activeCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 12]], ['$add' => ['$$value', 1]], '$$value']]]], 'cannotCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 15]], ['$add' => ['$$value', 1]], '$$value']]]], 'shutdownCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 13]], ['$add' => ['$$value', 1]], '$$value']]]]]], ['$match' => $match2], ['$group' => ['_id' => ['id' => $groupId, 'name' => $groupField], 'alreadyFollowNum' => ['$sum' => 1], 'alreadyFollowSecond' => ['$sum' => '$history_count'], 'successCount' => ['$sum' => '$successCount'], 'stopCount' => ['$sum' => '$stopCount'], 'noAnswerCount' => ['$sum' => '$noAnswerCount'], 'emptyCount' => ['$sum' => '$emptyCount'], 'wrongCount' => ['$sum' => '$wrongCount'], 'refuseCount' => ['$sum' => '$refuseCount'], 'activeCount' => ['$sum' => '$activeCount'], 'cannotCount' => ['$sum' => '$cannotCount'], 'shutdownCount' => ['$sum' => '$shutdownCount']]],['$sort' => ['alreadyFollowNum' => -1]]];

        $data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($pip, ['allowDiskUse' => true]);
        $data = iterator_to_array($data);

        foreach ($data as $key => $val) {
            $data[$key]['emptyAndWrongCount'] = $val['emptyCount'] + $val['wrongCount'];
            $data[$key]['successRate'] = number_format($val['successCount'] / $val['alreadyFollowSecond'] * 100, 2);
            $data[$key]['noAnswerRate'] = number_format($val['noAnswerCount'] / $val['alreadyFollowSecond'] * 100, 2);
            $data[$key]['emptyAndWrongRate'] = number_format($data[$key]['emptyAndWrongCount'] / $val['alreadyFollowSecond'] * 100, 2);
            $data[$key]['refuseRate'] = number_format($val['refuseCount'] / $val['alreadyFollowSecond'] * 100, 2);
            $data[$key]['activeRate'] = number_format($val['activeCount'] / $val['alreadyFollowSecond'] * 100, 2);
            $data[$key]['cannotRate'] = number_format($val['cannotCount'] / $val['alreadyFollowSecond'] * 100, 2);
            $data[$key]['stopRate'] = number_format($val['stopCount'] / $val['alreadyFollowSecond'] * 100, 2);
            $data[$key]['shutdownRate'] = number_format($val['shutdownCount'] / $val['alreadyFollowSecond'] * 100, 2);
        }
        return $data;
    }

    /**
     * 随访工作量
     * @param int $type 类型 1 按人员，2 按任务，3 按病种，4随访方式，5 自动生成统计
     * @return array
     */
    public function followWorkload(int $type): array
    {
        $requestData = request()->param();

        $match['deleted_at'] = 0;
        $match['mode'] = 4;

        //随访时间起
        if (isset($requestData['followTime'][0]) && !empty($requestData['followTime'][0])){
            $match['pushtime']['$gte'] = $requestData['followTime'][0];
        }
        //随访时间止
        if (isset($requestData['followTime'][1]) && !empty($requestData['followTime'][1])){
            $match['pushtime']['$lte'] = $requestData['followTime'][1];
        }
        //随访人员
        if (isset($requestData['follow_staff']) && !empty($requestData['follow_staff'])) {

            $match['follow_staff.user_id'] = (int)$requestData['follow_staff'];
        }
        //随访范围
        if (isset($requestData['follow_scope']) && !empty($requestData['follow_scope'])) {
            if ($requestData['follow_scope'] == 1) {
                $match2['bz.bingzhongArr.bingzhong_type'] = '1';
            }else{
                $match2['bz.bingzhongArr.bingzhong_type'] = ['$ne' => '1'];
            }
        }else{
            $match2 = (object) array();
        }

        //任务名称
        $where = [];
        if (isset($requestData['taskname']) && !empty($requestData['taskname'])) {
            $where[] = ['taskname', '=', ['$regex' => '^' . trim($requestData['taskname'])]];
        }
        //任务状态
        if (isset($requestData['status']) && !empty($requestData['status'])) {
            $where[] = ['status', '=', (int)$requestData['status']];
        }
        //创建任务时间
        if (isset($requestData['createTime'][0]) && !empty($requestData['createTime'][0])) {
            $where[] = ['created_at', '>=', strtotime($requestData['createTime'][0])];
        }
        if (isset($requestData['createTime'][1]) && !empty($requestData['createTime'][1])) {
            $where[] = ['created_at', '<=', strtotime($requestData['createTime'][1])];
        }

        switch ($type) {
            case 1:
                $match['followStatus'] = 1;

                $groups = ['_id' => '$patientId', 'id' => ['$last' => '$_id'], 'patientId' => ['$last' => '$patientId'], 'is_effective' => ['$last' => '$is_effective'], 'result' => ['$last' => '$result'], 'resultName' => ['$last' => '$resultName'], 'deptId' => ['$last' => '$patientDeptId'], 'bz' => ['$last' => '$bz.bingzhongArr'], 'follow_staff' => ['$last' => '$follow_staff']];

                $groups2 = ['_id' => ['id' => '$follow_staff.user_id'],'username' => ['$last' => '$follow_staff.username'],'alreadyFollowNum' => ['$sum' => 1], 'alreadyFollowSecond' => ['$sum' => '$history_count'], 'successCount' => ['$sum' => '$successCount'], 'stopCount' => ['$sum' => '$stopCount'], 'noAnswerCount' => ['$sum' => '$noAnswerCount'], 'emptyCount' => ['$sum' => '$emptyCount'], 'wrongCount' => ['$sum' => '$wrongCount'], 'refuseCount' => ['$sum' => '$refuseCount'], 'activeCount' => ['$sum' => '$activeCount'], 'cannotCount' => ['$sum' => '$cannotCount'], 'shutdownCount' => ['$sum' => '$shutdownCount'], 'recrudescenceCount' => ['$sum' => '$recrudescenceCount'], 'transferCount' => ['$sum' => '$transferCount'], 'dieCount' => ['$sum' => '$dieCount'], 'stableCount' => ['$sum' => '$stableCount'], 'otherCount' => ['$sum' => '$otherCount'], 'zyCount' => ['$sum' => '$zyCount'], 'mzCount' => ['$sum' => '$mzCount'], 'effectiveCount' => ['$sum' => '$effectiveCount'], 'invalidCount' => ['$sum' => '$invalidCount']];
                break;
            case 2:

                $task_id = (new FollowtaskModel())->where($where)->column('id');
                $task_id = array_map(function ($v) {
                    return new ObjectId($v);
                }, $task_id);
                $match['task_id'] = ['$in' => $task_id];

                $groups = ['_id' => '$patientId', 'id' => ['$last' => '$_id'], 'patientId' => ['$last' => '$patientId'], 'is_effective' => ['$last' => '$is_effective'], 'result' => ['$last' => '$result'], 'resultName' => ['$last' => '$resultName'], 'deptId' => ['$last' => '$patientDeptId'], 'bz' => ['$last' => '$bz.bingzhongArr'], 'follow_staff' => ['$last' => '$follow_staff'], 'task_id' => ['$last' => '$task_id'], 'task_name' => ['$last' => '$taskname'], 'followStatus' => ['$last' => '$followStatus']];

                $groups2 = ['_id' => ['task_id' => '$task_id', 'user_id' => '$follow_staff.user_id'],'task_name' => ['$last' => '$task_name'],'username' => ['$last' => '$follow_staff.username'],'alreadyFollowNum' => ['$sum' => 1], 'alreadyFollowSecond' => ['$sum' => '$history_count'], 'successCount' => ['$sum' => '$successCount'], 'stopCount' => ['$sum' => '$stopCount'], 'noAnswerCount' => ['$sum' => '$noAnswerCount'], 'emptyCount' => ['$sum' => '$emptyCount'], 'wrongCount' => ['$sum' => '$wrongCount'], 'refuseCount' => ['$sum' => '$refuseCount'], 'activeCount' => ['$sum' => '$activeCount'], 'cannotCount' => ['$sum' => '$cannotCount'], 'shutdownCount' => ['$sum' => '$shutdownCount'], 'recrudescenceCount' => ['$sum' => '$recrudescenceCount'], 'transferCount' => ['$sum' => '$transferCount'], 'dieCount' => ['$sum' => '$dieCount'], 'stableCount' => ['$sum' => '$stableCount'], 'otherCount' => ['$sum' => '$otherCount'], 'zyCount' => ['$sum' => '$zyCount'], 'mzCount' => ['$sum' => '$mzCount'], 'effectiveCount' => ['$sum' => '$effectiveCount'], 'invalidCount' => ['$sum' => '$invalidCount'], 'completedCount' => ['$sum' => ['$cond' => [['$eq' => ['$followStatus', 1]], 1, 0]]]];
                break;
            case 3:
                $match['followStatus'] = 1;
                $groups = ['_id' => '$patientId', 'id' => ['$last' => '$_id'], 'patientId' => ['$last' => '$patientId'], 'is_effective' => ['$last' => '$is_effective'], 'result' => ['$last' => '$result'], 'resultName' => ['$last' => '$resultName'], 'deptId' => ['$last' => '$patientDeptId'], 'bz' => ['$last' => '$bz.bingzhongArr']];

                $groups2 = ['_id' => ['bz_id' => '$bz.bingzhong_id'],'bz_name' => ['$last' => '$bz.bingzhong_name'],'alreadyFollowNum' => ['$sum' => 1], 'alreadyFollowSecond' => ['$sum' => '$history_count'], 'successCount' => ['$sum' => '$successCount'], 'stopCount' => ['$sum' => '$stopCount'], 'noAnswerCount' => ['$sum' => '$noAnswerCount'], 'emptyCount' => ['$sum' => '$emptyCount'], 'wrongCount' => ['$sum' => '$wrongCount'], 'refuseCount' => ['$sum' => '$refuseCount'], 'activeCount' => ['$sum' => '$activeCount'], 'cannotCount' => ['$sum' => '$cannotCount'], 'shutdownCount' => ['$sum' => '$shutdownCount'], 'recrudescenceCount' => ['$sum' => '$recrudescenceCount'], 'transferCount' => ['$sum' => '$transferCount'], 'dieCount' => ['$sum' => '$dieCount'], 'stableCount' => ['$sum' => '$stableCount'], 'otherCount' => ['$sum' => '$otherCount'], 'zyCount' => ['$sum' => '$zyCount'], 'mzCount' => ['$sum' => '$mzCount'], 'effectiveCount' => ['$sum' => '$effectiveCount'], 'invalidCount' => ['$sum' => '$invalidCount']];
                break;
            case 4:
                $match['followStatus'] = 1;
                return $this->followMethod($match);
            case 5:
                $match['followStatus'] = 1;
                return $this->automaticGeneration($match);
            default:
        }
        $pip = [['$match' => $match], ['$unwind' => ['path' => '$bz.bingzhongArr', 'preserveNullAndEmptyArrays' => false]], ['$match' => $match2], ['$group' => $groups], ['$lookup' => ['from' => 'follow_history', 'localField' => 'id', 'foreignField' => 'follow_id', 'as' => 'history']], ['$addFields' => ['history_count' => ['$size' => '$history'], 'successCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.resultIsEffective', 1]], ['$add' => ['$$value', 1]], '$$value']]]], 'stopCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 14]], ['$add' => ['$$value', 1]], '$$value']]]], 'noAnswerCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 17]], ['$add' => ['$$value', 1]], '$$value']]]], 'emptyCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 10]], ['$add' => ['$$value', 1]], '$$value']]]], 'wrongCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 16]], ['$add' => ['$$value', 1]], '$$value']]]], 'refuseCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 8]], ['$add' => ['$$value', 1]], '$$value']]]], 'activeCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 12]], ['$add' => ['$$value', 1]], '$$value']]]], 'cannotCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 15]], ['$add' => ['$$value', 1]], '$$value']]]], 'shutdownCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 13]], ['$add' => ['$$value', 1]], '$$value']]]], 'recrudescenceCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 6]], ['$add' => ['$$value', 1]], '$$value']]]], 'transferCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 27]], ['$add' => ['$$value', 1]], '$$value']]]], 'dieCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 19]], ['$add' => ['$$value', 1]], '$$value']]]], 'stableCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 28]], ['$add' => ['$$value', 1]], '$$value']]]], 'otherCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 11]], ['$add' => ['$$value', 1]], '$$value']]]], 'zyCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 24]], ['$add' => ['$$value', 1]], '$$value']]]], 'mzCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 25]], ['$add' => ['$$value', 1]], '$$value']]]], 'effectiveCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.resultIsEffective', 1]], ['$add' => ['$$value', 1]], '$$value']]]], 'invalidCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.resultIsEffective', 0]], ['$add' => ['$$value', 1]], '$$value']]]]]], ['$group' => $groups2]];
        $data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($pip, ['allowDiskUse' => true]);
        $data = iterator_to_array($data);

        foreach ($data as $key => $val) {
            $data[$key]['lossCount'] = $val['emptyCount'] + $val['wrongCount'] + $val['refuseCount'];
        }
        return $data;
    }

    /**
     * 随访工作量-随访方式
     * @param array $match
     * @return array
     */
    public function followMethod(array $match=[]): array
    {
        $pip = [['$match' => $match], ['$group' => ['_id' => '$patientId', 'id' => ['$last' => '$_id'], 'mode' => ['$last' => '$mode']]], ['$lookup' => ['from' => 'follow_history', 'localField' => 'id', 'foreignField' => 'follow_id', 'as' => 'history']], ['$addFields' => ['history_count' => ['$size' => '$history'], 'stopCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 14]], ['$add' => ['$$value', 1]], '$$value']]]], 'noAnswerCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 17]], ['$add' => ['$$value', 1]], '$$value']]]], 'emptyCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 10]], ['$add' => ['$$value', 1]], '$$value']]]], 'wrongCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 16]], ['$add' => ['$$value', 1]], '$$value']]]], 'refuseCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 8]], ['$add' => ['$$value', 1]], '$$value']]]], 'activeCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 12]], ['$add' => ['$$value', 1]], '$$value']]]], 'cannotCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 15]], ['$add' => ['$$value', 1]], '$$value']]]], 'shutdownCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 13]], ['$add' => ['$$value', 1]], '$$value']]]], 'recrudescenceCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 6]], ['$add' => ['$$value', 1]], '$$value']]]], 'transferCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 27]], ['$add' => ['$$value', 1]], '$$value']]]], 'dieCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 19]], ['$add' => ['$$value', 1]], '$$value']]]], 'stableCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 28]], ['$add' => ['$$value', 1]], '$$value']]]], 'otherCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 11]], ['$add' => ['$$value', 1]], '$$value']]]], 'effectiveCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.resultIsEffective', 1]], ['$add' => ['$$value', 1]], '$$value']]]], 'invalidCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.resultIsEffective', 0]], ['$add' => ['$$value', 1]], '$$value']]]]]], ['$group' => ['_id' => ['mode' => '$mode'], 'mode' => ['$last' => '$mode'], 'alreadyFollowNum' => ['$sum' => 1], 'alreadyFollowSecond' => ['$sum' => '$history_count'], 'stopCount' => ['$sum' => '$stopCount'], 'noAnswerCount' => ['$sum' => '$noAnswerCount'], 'emptyCount' => ['$sum' => '$emptyCount'], 'wrongCount' => ['$sum' => '$wrongCount'], 're4fuseCount' => ['$sum' => '$refuseCount'], 'activeCount' => ['$sum' => '$activeCount'], 'cannotCount' => ['$sum' => '$cannotCount'], 'shutdownCount' => ['$sum' => '$shutdownCount'], 'recrudescenceCount' => ['$sum' => '$recrudescenceCount'], 'transferCount' => ['$sum' => '$transferCount'], 'dieCount' => ['$sum' => '$dieCount'], 'stableCount' => ['$sum' => '$stableCount'], 'otherCount' => ['$sum' => '$otherCount'], 'effectiveCount' => ['$sum' => '$effectiveCount'], 'invalidCount' => ['$sum' => '$invalidCount']]]];
        $data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($pip, ['allowDiskUse' => true]);
        $data = iterator_to_array($data);
        foreach ($data as $key => $val) {
            $data[$key]['lossCount'] = $val['emptyCount'] + $val['wrongCount'] + $val['refuseCount'];
        }

        $conMatch['mode'] = ['$in' => ['门诊', '住院']];
        $conMatch['deleted_at'] = 0;
        $conPip = [['$match' => $conMatch], ['$group' => ['_id' => '$patientId', 'patientId' => ['$last' => '$patientId'], 'alreadyFollowSecond' => ['$sum' => 1], 'mode' => ['$last' => '$mode']]], ['$lookup' => ['from' => 'patient_info', 'localField' => 'patientId', 'foreignField' => 'patientId', 'as' => 'info']], ['$unwind' => ['path' => '$info', 'preserveNullAndEmptyArrays' => true]], ['$group' => ['_id' => '$mode', 'mode' => ['$last' => '$mode'], 'alreadyFollowNum' => ['$sum' => 1], 'alreadyFollowSecond' => ['$sum' => '$alreadyFollowSecond'], 'survival' => ['$sum' => ['$cond' => [['$eq' => ['$info.liveStatus', '1']], 1, 0]]], 'death' => ['$sum' => ['$cond' => [['$eq' => ['$info.liveStatus', '0']], 1, 0]]]]]];
        $conData = ZhyxMongo::getInstance()->setCollection('follow_history')->aggregate($conPip, ['allowDiskUse' => true]);
        $conData = iterator_to_array($conData);
        return [
            'modeList' => $data??[],
            'conList' => $conData
        ];
    }

    /**
     * 随访工作量-随访方式
     * @param array $match
     * @return array
     */
    public function automaticGeneration(array $match=[]): array
    {
        $pip = [['$match' => $match], ['$unwind' => ['path' => '$bz.bingzhongArr', 'preserveNullAndEmptyArrays' => false]], ['$match' => ['bz.bingzhongArr.bingzhong_type' => '1']], ['$group' => ['_id' => '$patientId', 'id' => ['$last' => '$_id'], 'patientId' => ['$last' => '$patientId'], 'bz' => ['$last' => '$bz.bingzhongArr']]], ['$lookup' => ['from' => 'follow_history', 'localField' => 'patientId', 'foreignField' => 'patientId', 'as' => 'history']], ['$addFields' => ['history_count' => ['$size' => '$history'], 'is_effective' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.resultIsEffective', 1]], ['$add' => ['$$value', 1]], '$$value']]]], 'zyCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 24]], ['$add' => ['$$value', 1]], '$$value']]]], 'mzCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 25]], ['$add' => ['$$value', 1]], '$$value']]]], 'dieCount' => ['$reduce' => ['input' => '$history', 'initialValue' => 0, 'in' => ['$cond' => [['$eq' => ['$$this.result', 19]], ['$add' => ['$$value', 1]], '$$value']]]]]], ['$group' => ['_id' => ['bz_id' => '$bz.bingzhong_id'], 'bingzhong_name' => ['$last' => '$bz.bingzhong_name'], 'alreadyFollowNum' => ['$sum' => 1], 'alreadyFollowSecond' => ['$sum' => '$history_count'], 'is_effective' => ['$sum' => '$is_effective'], 'zyCount' => ['$sum' => '$zyCount'], 'mzCount' => ['$sum' => '$mzCount'], 'dieCount' => ['$sum' => '$dieCount']]]];

        $data = ZhyxMongo::getInstance()->setCollection('follow')->aggregate($pip, ['allowDiskUse' => true]);
        $data = iterator_to_array($data);
        foreach ($data as $key => $val) {
            $data[$key]['successRate'] = number_format($val['is_effective'] / $val['alreadyFollowSecond'] * 100, 2);
        }
        return $data;
    }

    /**
     * 电话方式统计
     * @return Paginator
     */
    public function telMethodStatistics(): Paginator
    {
        $req = request()->param();

        $patientModel = (new PatientInfoModel());

        $patientWhere = [];
        if (isset($req['medicalRecordsNo']) && !empty($req['medicalRecordsNo'])) {
            $patientWhere[] = ['medicalRecordsNo', '=', trim($req['medicalRecordsNo'])];
        }

        if (isset($req['first_treat_datetime'][0]) && !empty($req['first_treat_datetime'][0]) && $req['first_treat_datetime'][0] <> null && $req['first_treat_datetime'][0] <> '') {
            $patientWhere[] = ['first_treat_datetime', '>=', $req['first_treat_datetime'][0]];
        }

        if (isset($req['first_treat_datetime'][1]) && !empty($req['first_treat_datetime'][1]) && $req['first_treat_datetime'][1] <> null && $req['first_treat_datetime'][1] <> '') {
            $patientWhere[] = ['first_treat_datetime', '<=', $req['first_treat_datetime'][1]];
        }


        if (isset($req["bz"]) && !empty($req["bz"])) {
            $patientWhere[] = ['bz.bingzhongArr.bingzhong_id', 'in', $req["bz"]];
        }

        if (isset($req['outhospitalDept']) && !empty($req["outhospitalDept"])) {
            $patientWhere[] = ['hoList.inhospitalDept', '=', ['$regex' => '^' . trim($req['outhospitalDept'])]];
        }

        if (!empty($patientWhere)) {

            $patientIds = $patientModel->where($patientWhere)->cache(true, 3600)->column('patientId');

            if (!$patientIds) {
                throw new FailedException('没匹配到数据');
            }
            $where[] = ['patientId', 'in', $patientIds];
        }

        $where[] = ['mode', '=', 4];
        $field = 'staffName,name,patientId,contactNumber,diagnosis,pushtime,resultName';
        $list = (new FollowHistory())->getDataList($where, $field, ['medicalRecordsNo', 'first_treat_datetime', 'bz', 'outhospitalDept']);
        $list->each(function ($item, $key) use ($patientModel){
            $info = $patientModel->where('patientId', $item['patientId'])
                ->field('sex,first_treat_datetime')
                ->find();
            $item['sex'] = $info['sex']??'';
            $item['first_treat_datetime'] = $info['first_treat_datetime']??'';
            return $item;
        });
        return $list;
    }

    /**
     * 计算km生存率
     * @return array
     */
    private function kmSurvivalRate($data): array
    {
        $time_points = [3, 6, 9, 12, 24, 36, 48, 60];
        $probabilities = [];
        foreach ($data as $key => $val) {
            //随访率
            $follow_up_rate = ($val['beforeDieNum'] + $val['alreadyFollowNum']) / $val['shouldFollowNum'] * 100;
            if ($follow_up_rate > 100) {
                $data[$key]['follow_up_rate'] = '100.00'.'%';
                #break;
            }else{
                $data[$key]['follow_up_rate'] = number_format($follow_up_rate, 2).'%';
            }

            //有效随访率
            $valid_follow_rate = ($val['beforeDieNum'] + $val['effectiveNum']) / $val['shouldFollowNum'] * 100;
            if ($follow_up_rate > 100) {
                $data[$key]['valid_follow_rate'] = '100.00'.'%';
            }else{
                $data[$key]['valid_follow_rate'] = number_format($valid_follow_rate, 2).'%';
            }

            //死亡率
            $death_rate = ($val['beforeDieNum'] + $val['dieNum']) / $val['shouldFollowNum'] * 100;

            if ($death_rate > 100) {
                $data[$key]['death_rate'] = '100.00'.'%';
            }else{
                $data[$key]['death_rate'] = number_format($death_rate, 2).'%';
            }


            // 计算生存概率
            $at_risk = $val['shouldFollowNum'] - ($val['beforeLossNum'] + $val['beforeDieNum']);
            $flag = '';
            foreach ($time_points as $time_point) {
                $prob = 1.0;
                for ($i = 0; $i < $time_point; $i++) {
                    $prob *= ($at_risk - $i - $val['beforeDieNum']) / ($at_risk - $i);
                }
                $probabilities[$time_point.'月'] = number_format($prob * 100, 2).'%';

                if (($prob * 100) < 0 || ($prob * 100) > 100) {
                    $probabilities[$time_point.'月'] = '--';
                    $flag = 1;
                }

                if ($flag === 1) {
                    $probabilities[$time_point.'月'] = '--';
                }
            }
            $data[$key]['probabilities'] = $probabilities;
        }
        return $data;
    }
}